#include "tf.h"

#include "io.h"

#include "mmc.h"

static struct mmc tf_mmc;

static void tf_select(void)
{
    GPIO_ResetBits(SD_CS_GPIO_PORT, SD_CS_PIN);
}

static void tf_release(void)
{
    GPIO_SetBits(SD_CS_GPIO_PORT, SD_CS_PIN);
}

static void SD_SPI_SetSpeed(uint16_t SPI_BaudRatePrescaler)
{
  if((SPI_BaudRatePrescaler & (uint16_t)0x0038) == SPI_BaudRatePrescaler)
  {
    SD_SPI->CR1 = (SD_SPI->CR1 & (uint16_t)0xFFC7) |SPI_BaudRatePrescaler;
 
    SPI_Cmd(SD_SPI, ENABLE);
  }
}

static void tf_lowlevel_init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef   SPI_InitStructure;
	
  RCC_APB2PeriphClockCmd(SD_CS_GPIO_CLK | SD_SPI_MOSI_GPIO_CLK | SD_SPI_MISO_GPIO_CLK |
                         SD_SPI_SCK_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);

  /*!< SD_SPI Periph clock enable */
  if (SPI3 == SD_SPI)
  {
    RCC_APB1PeriphClockCmd(SD_SPI_CLK, ENABLE);
  }
  else
  {
    RCC_APB2PeriphClockCmd(SD_SPI_CLK, ENABLE);
  }
  
  /*!< Configure SD_SPI pins: SCK */
  GPIO_InitStructure.GPIO_Pin = SD_SPI_SCK_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(SD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

  /*!< Configure SD_SPI pins: MISO */
  GPIO_InitStructure.GPIO_Pin = SD_SPI_MISO_PIN;
  GPIO_Init(SD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

  /*!< Configure SD_SPI pins: MOSI */
  GPIO_InitStructure.GPIO_Pin = SD_SPI_MOSI_PIN;
  GPIO_Init(SD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

  /*!< Configure SD_SPI_CS_PIN pin: SD Card CS pin */
  GPIO_InitStructure.GPIO_Pin = SD_CS_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(SD_CS_GPIO_PORT, &GPIO_InitStructure);

  /*!< SD_SPI Config */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SD_SPI, &SPI_InitStructure);
  
  SPI_Cmd(SD_SPI, ENABLE); /*!< SD_SPI enable */
}

static sd_err tf_open(struct mmc *mmc)
{
    tf_lowlevel_init();
  
    SD_SPI_SetSpeed(SPI_BaudRatePrescaler_256);
    
    return 0;
}

static os_u8 tf_read_write(os_u8 Data)
{
  while(SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET)
  { }
  
  SPI_I2S_SendData(SD_SPI, Data);
  
  while(SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_RXNE) == RESET)
  { }
  
  return SPI_I2S_ReceiveData(SD_SPI);
}

err_t tf_configuration(void)
{
    tf_mmc.open = tf_open;
    tf_mmc.select = tf_select;
    tf_mmc.release = tf_release;
    tf_mmc.read_write = tf_read_write;
  
    return mmc_open(&tf_mmc);
}
